# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: inkyu

import datetime
import functools
import logging

import memcache
from absl import app, flags
from tornado.ioloop import IOLoop

import coin.flow.subscriber as flow_subscriber
from coin.flow.simple_queue import SimpleQueue
from coin.strategy.hk_hard_arb.balance_printer1 import FungibleArbProducts
from coin.strategy.hk_hard_arb.util import load_clean_json
from coin.strategy.mm.base.multi_feed_subsystem import MultiFeedSubsystem
from coin.strategy.mm.feed import SubscriptionRequest, get_flow_book_builder_cls
from coin.util.basis_util import BasisStorage

FLAGS = flags.FLAGS

flags.DEFINE_string('exchanges', 'Exchanges', '')

flags.DEFINE_string('config_filename', '', '')

flags.DEFINE_integer('exit_after_min', 30, '')

flags.DEFINE_string('basis_memcached_serverspec', None, 'memcached ServerSpec')


def _gen_memcached_client():
  serverspec = flags.FLAGS.basis_memcached_serverspec
  if serverspec is not None:
    mc_spec = serverspec.split(',')
    mc = memcache.Client(mc_spec)
    assert mc is not None, mc
    return mc
  else:
    return None


class ArbStrategy(object):
  def __init__(self, strategy_params):
    self._logger = logging.getLogger(__name__)

    self._feed = MultiFeedSubsystem()
    self._config = strategy_params['config']

    exchange_0 = strategy_params['exchange_0']
    exchange_1 = strategy_params['exchange_1']

    # TODO(someone): Need some unified metaclass
    self._book_builder_clses = (
        get_flow_book_builder_cls(SubscriptionRequest('Spot', exchange_0, None)),
        get_flow_book_builder_cls(SubscriptionRequest('Spot', exchange_1, None)),
    )

    self._arb_product = None
    self._basis_storage = BasisStorage()
    self._mc = _gen_memcached_client()

  def subscribe_feeds(self):
    common_config = self._config['common']

    self._arb_product = FungibleArbProducts.two(common_config['quote_currency'],
                                                self._config['products'].keys(),
                                                self._book_builder_clses[0].ProductType,
                                                self._book_builder_clses[1].ProductType)

    self._feed.subscribe_book(self._arb_product.native_0.products,
                              functools.partial(self._on_book, 0))
    self._feed.subscribe_book(self._arb_product.native_1.products,
                              functools.partial(self._on_book, 1))

    # TODO(yongwoon): setup basis

  def start(self, ioloop, queue, flow_sub):
    self._ioloop = ioloop
    self._feed.start(ioloop, queue, flow_sub)
    self.save_basis(periodic=True)

  def _on_book(self, exchange_id, book):
    print(book)

    # TODO(yongwoon): setup basis
    if self._basis_storage is not None:
      pass
      # self._basis_storage.update_basis(key_a, key_b)
    return True

  def save_basis(self, periodic=False):
    # TODO(yongwoon): setup basis
    if self._basis_storage is not None:
      key = "test"
      value = "test"
      # value = self._basis_storage.get_basis()
      self._mc.set(key, value)
    if periodic:
      self._ioloop.add_timeout(datetime.timedelta(seconds=10), self.save_basis, True)


def get_param_set(exchanges, config_filename):
  exchange_0, exchange_1 = exchanges.split(',')
  config = load_clean_json(config_filename)
  return {
      'exchange_0': exchange_0,
      'exchange_1': exchange_1,
      'config': config,
  }


def main(argv):
  strategy_params = get_param_set(exchanges=FLAGS.exchanges, config_filename=FLAGS.config_filename)

  queue = SimpleQueue('hard_arb')
  flow_sub = flow_subscriber.from_queue(queue)
  ioloop = IOLoop.current()
  strategy = ArbStrategy(strategy_params)  # TODO(inkyu): DRY_RUN
  strategy.subscribe_feeds()
  strategy.start(ioloop, queue, flow_sub)

  exit_after = datetime.timedelta(minutes=FLAGS.exit_after_min)
  ioloop.add_timeout(exit_after, ioloop.stop)
  ioloop.start()


if __name__ == '__main__':
  logging.basicConfig(level='DEBUG', format='%(levelname)8s %(asctime)s %(name)s] %(message)s')
  app.run(main)
